#include "buffer.h"
#include <stdio.h>

namespace rr {
namespace nio {

Buffer::Buffer(int32_t init_size, int32_t max_size)
: max_size_(max_size)
, reader_index_(kCheapPrepend)
, writer_index_(kCheapPrepend)
{
    data_.resize(init_size+kCheapPrepend);
}

void Buffer::Clear()
{
    RetrieveAll();
}

void Buffer::Retrieve(size_t len)
{
    if(len < ReadableBytes()) {
        reader_index_ += len;
    } else {
        RetrieveAll();
    }
}

void Buffer::RetrieveAll()
{
    reader_index_ = kCheapPrepend; 
    writer_index_ = kCheapPrepend;
}

bool Buffer::EnsureWritableBytes(size_t len)
{
    if(WritableBytes() >= len) {
        return true;
    }

    return MakeSpace(len);
}

bool Buffer::Append(const char* data, size_t len)
{
    if( 0 == len) {
        return true;
    }    

    if(!EnsureWritableBytes(len)){
        return false;
    }

    std::copy(data, data+len, BeginWrite());
	HasWritten(len);

    return true;
}

bool Buffer::MakeSpace(size_t len)
{
    if(WritableBytes() + PrependableBytes() >= len + kCheapPrepend) {
        size_t read_able = ReadableBytes();
		std::copy(Begin() + reader_index_, Begin() + writer_index_, Begin() + kCheapPrepend);
		reader_index_ = kCheapPrepend;
		writer_index_ = reader_index_ + read_able;
        printf("MakeSpace len:%zu read_able:%zu\n", len, read_able);
        return true;
    }

    //需扩容
    size_t expend_size = len + kCheapPrepend - WritableBytes() - PrependableBytes();
    if(data_.size() + expend_size > max_size_+kCheapPrepend) {
        printf("Buffer is full want len:%zu expend_size:%zu buf size:%zu max size:%d read:%zu write:%zu\n", 
                len, expend_size, data_.size(), max_size_, reader_index_, writer_index_);
        return false;
    }

    std::vector<char> new_data(data_.size() + expend_size);
    size_t read_able = ReadableBytes();
    std::copy(Begin() + reader_index_, Begin() + writer_index_, &*new_data.begin() + kCheapPrepend);
    reader_index_ = kCheapPrepend;
	writer_index_ = reader_index_ + read_able;
    new_data.swap(data_);

    printf("Buffer::MakeSpace len:%zu expend_size:%zu size:%zu read_able:%zu\n", len, expend_size, data_.size(), read_able);

    return true;
}

} //namespace 
} //namespace 
